
#[cfg(feature = "ssr")]
use crate::prelude::{FieldType, DataType};
#[cfg(feature = "ssr")]
use arc_swap::ArcSwap;
#[cfg(feature = "ssr")]
use common_page::CommonPage;
#[cfg(feature = "ssr")]
use once_cell::sync::Lazy;
#[cfg(feature = "ssr")]
use std::{collections::HashMap, fs, sync::Arc};

pub mod column;
pub mod common_page;
pub mod default_value;
pub mod form_props;
pub mod import_props;
pub mod list_props;
pub mod parameter;
pub mod report_props;

#[cfg(feature = "ssr")]
use crate::base::{Error, Result};
#[cfg(feature = "ssr")]
static PAGE_CONFS: Lazy<ArcSwap<HashMap<String, &'static CommonPage>>> =
    Lazy::new(|| ArcSwap::from_pointee(HashMap::new()));
#[cfg(feature = "ssr")]
pub async fn init_page_config() -> Result<()> {
    use crate::base::get_config_path;
    let conf_path = format!("{}/page_confs", get_config_path());
    let dir = fs::read_dir(&conf_path)?;
    let mut confs: HashMap<String, &'static CommonPage> = HashMap::new();
    for entry in dir {
        let conf_file = entry?;
        let path = &conf_file.path();
        let ext = path
            .extension()
            .map_or("", |v| v.to_str().map_or("", |v| v));
        if path.is_file() && ext == "yaml" {
            let os_file_name = &conf_file.file_name();
            let file_name = os_file_name.to_str().unwrap();
            let flen = file_name.len();
            let conf_str = fs::read_to_string(path)?;
            let rept_name = file_name[0..flen - 5].to_string();
            let mut conf: CommonPage = serde_yaml::from_str(&conf_str).or_else(|err| {
                Err(Error::from(format!(
                    "解析配置文件{}出错，错误信息{}",
                    &rept_name, err
                )))
            })?;
            conf.parse().await.or_else(|err| {
                Err(Error::from(format!(
                    "验证配置文件{}出错，错误信息{}",
                    &rept_name, err
                )))
            })?;
            confs.insert(rept_name, Box::leak(Box::new(conf)));
        }
    }
    PAGE_CONFS.store(Arc::new(confs));
    Ok(())
}
#[cfg(feature = "ssr")]
pub async fn reload_page_config(path: &std::path::Path) -> Result<()> {
    let file_name = path.file_name().unwrap().to_str().unwrap();
    if !file_name.ends_with(".yaml") {
        return Ok(());
    }
    let page_name = &file_name[0..file_name.len() - 5];
    let conf_str = fs::read_to_string(path)?;
    let mut conf: CommonPage = serde_yaml::from_str(&conf_str).or_else(|err| {
        Err(Error::from(format!(
            "解析页面配置文件{}出错，错误信息{}",
            page_name, err
        )))
    })?;
    conf.parse().await.or_else(|err| {
        Err(Error::from(format!(
            "解析面配置文件{}出错，错误信息{}",
            &page_name, err
        )))
    })?;
    let conf_ref = Box::leak(Box::new(conf));
    let conf_map = PAGE_CONFS.load().clone();
    let mut conf_map2: HashMap<String, &'static CommonPage> = HashMap::new();
    for (k, v) in conf_map.iter() {
        if k == page_name {
            conf_map2.insert(k.clone(), conf_ref);
        } else {
            conf_map2.insert(k.clone(), *v);
        }
    }
    PAGE_CONFS.store(Arc::new(conf_map2));
    Ok(())
}
#[cfg(feature = "ssr")]
pub fn get_page_config(name: &str) -> Result<&'static CommonPage> {
    match PAGE_CONFS.load().get(name) {
        Some(conf) => Ok(conf),
        None => Err(Error::Conf(format!("页面配置文件{}不存在", name))),
    }
}
#[cfg(feature = "ssr")]
pub fn valid_val_by_field_type(data_type: FieldType, val: &str) -> anyhow::Result<()> {
    use chrono::{NaiveDate, NaiveDateTime};
    match data_type {
        FieldType::Bool => {val.parse::<bool>()?;},
        FieldType::UInt8 => {val.parse::<u8>()?;},
        FieldType::UInt16 => {val.parse::<u16>()?;},
        FieldType::UInt32 => {val.parse::<u32>()?;},
        FieldType::UInt64 => {val.parse::<u64>()?;},
        FieldType::Int8 => {val.parse::<i8>()?;},
        FieldType::Int16 => {val.parse::<i16>()?;},
        FieldType::Int32 => {val.parse::<i32>()?;},
        FieldType::Int64 => {val.parse::<i64>()?;},
        FieldType::Float32 => {val.parse::<f32>()?;},
        FieldType::Float64 => {val.parse::<f64>()?;},
        FieldType::Decimal(_, _) => {val.parse::<f64>()?;},
        FieldType::String(l) => {
            if val.len() > l as usize{
                anyhow::bail!("字符串长度超过最大限制{}", l)
            }
        },
        FieldType::Date => {
            let fmt = if val.len() == 8 { "%Y%m%d" } else { "%Y-%m-%d" };
            NaiveDate::parse_from_str(val, fmt)?;
        }
        FieldType::Datetime => {
            let fmt = if val.len() == 17 { "%Y%m%d %H%M%S" } else { "%Y-%m-%d %H:%M:%S" };
            NaiveDateTime::parse_from_str(val,fmt)?;
        },
    };
    Ok(())
}

#[cfg(feature = "ssr")]
pub fn valid_val_by_data_type(data_type: DataType, val: &str) -> anyhow::Result<()> {
    use chrono::{NaiveDate, NaiveDateTime};
    match data_type {
        DataType::Bool => {val.parse::<bool>()?;},
        DataType::Int => {val.parse::<i64>()?;},
        DataType::Float => {val.parse::<f64>()?;},
        DataType::String => {},
        DataType::Date => {
            let fmt = if val.len() == 8 { "%Y%m%d" } else { "%Y-%m-%d" };
            NaiveDate::parse_from_str(val, fmt)?;
        }
        DataType::Datetime => {
            let fmt = if val.len() == 17 { "%Y%m%d %H%M%S" } else { "%Y-%m-%d %H:%M:%S" };
            NaiveDateTime::parse_from_str(val,fmt)?;
        },
    };
    Ok(())
}

